package core.wm;

import core.utils.EPara;
import core.rb.r.MR;
import java.util.HashMap;
import java.util.LinkedList;

/*Author: John Archer, Contact: john.archer.jpa@gmail.com*/
public class WM {
    private int kSize;
    private String ref;
    private double kDen;
    private HashMap <String, LinkedList <Integer>> lib;

    public WM(String ref, HashMap <String, LinkedList <Integer>>  lib, int s, double d) {
        this.ref = ref;
        this.kSize = s;
        this.kDen = d;
        this.lib = lib;
    }

    public MR doMatch(String readSeq, String qScores, boolean reversed, int index) {
        LinkedList <Integer> hits = scanner(readSeq);
        int[] tCov = getCover(hits);
        MR wmr = getRead(tCov, readSeq, qScores, reversed, index);
        return wmr;
    }

    private LinkedList <Integer> scanner(String read){
        LinkedList <Integer> hits = new LinkedList();
        int noOfWordsInRead = read.length() - (kSize - 1);
        for (int t = 0; t < noOfWordsInRead; t += EPara.WORD_SKIP) {
            String word = read.substring(t, t + kSize);
            if(lib.containsKey(word)){hits.addAll(lib.get(word));}
        }
        return hits;
    }

    private int[] getCover(LinkedList <Integer> hits) {
        int cov[] = new int[ref.length()];
        for(int x=0; x<hits.size();x++){
            for (int y = 0; y < kSize; y++) {cov[(hits.get(x).intValue() + y)]++;}
        }
        return cov;
    }

    private MR getRead(int [] tCov, String read, String qs, boolean rev, int index) {
        int wlen = read.length()+10; int maxCov = 0;
        int bStart = 0; int noOfWins = tCov.length - wlen;
        int jump = 20;
        for (int x = 0; x < noOfWins; x = x + jump) {
            int sum = 0;
            for (int y = 0; y < wlen; y++) {sum = sum + tCov[x + y];}
            if (sum > maxCov) {
                maxCov = sum;
                bStart = x;
            }
        }
        int sub = jump - 1;
        for (int x = bStart - sub; x < bStart + sub && x > 0 && x < noOfWins; x++) {
            int sum = 0;
            for (int y = 0; y < wlen; y++) {sum += tCov[x + y];}
            if (sum > maxCov) {
                maxCov = sum;
                bStart = x;
            }
        }
        int currTEnd = ((bStart + wlen)>tCov.length) ? tCov.length - 1 : (bStart + wlen);
        double perNucCov = ((double) maxCov / wlen);
        if (perNucCov > kDen) {
            int trueEnd = bStart + read.length();
            if (bStart < 0) {
                int toTrim = Math.abs(bStart);
                read = new String(read.substring(toTrim));
                qs = new String(qs.substring(toTrim));
                bStart = 0;
            } else if (trueEnd > tCov.length) {
                int toTrim = trueEnd - tCov.length;
                int toKeep = read.length() - toTrim;
                read = new String(read.substring(0, toKeep));
                qs = new String(qs.substring(0, toKeep));
                currTEnd = tCov.length;
            }
            return new MR(read, qs, bStart, currTEnd, rev, index);
        }
        return null;
    }
}